Drag and Drop table content with JavaScript

Content of HTML table cells can be dragged to another cell or another table. It isn’t difficult to define onMouseMove handler and change top / left element styles to move the object. In case with tables, you will have to determine somehow target cell. Attaching onMouseOver handler on TD elements will not work, because browser doesn’t fire events to the elements below the dragged object.

Anyway, after taking care of the current scroll position and calculating TD positions, REDIPS.drag should work in recent major browsers like Google Chrome, Firefox, Safari, Internet Explorer, Opera and mobile devices as well. Click on image below, will open live demo where you can drag green, blue or orange bordered DIV elements, change properties (radio button and check-boxes) and click on “Save” button.

Download latest version redips2.tar.gz


REDIPS.drag example01

In this example “Save” button will scan table content, create query string and send to PHP page. Demo shows how to collect content and accept parameters on the server side. More about accepting parameters you can read at Reading multiple parameters in PHP. “Clone” elements (orange in this demo) will be duplicated first because of “redips-clone” keyword contained in class name. If you drop object on cell named “Trash”, object will be deleted from the table (with or without confirmation). Library has built in autoscroll and option to forbid landing to non empty cells or cells named with class “redips-mark”. Table can contain rowspan / colspan TDs and different background color for every cell.

Here are minimal steps to enable content dragging in table:

  • put <script type=”text/javascript” src=”redips-drag-min.js”></script> to the head section
  • initialize REDIPS.drag library: <body onload=”REDIPS.drag.init()”>
  • place table(s) inside <div id=”redips-drag”> to enable content dragging
  • place <div class=”redips-drag”>Hello World</div> to the table cell

Other features of REDIPS.drag library:

  • methods and data structure are defined in namespace (easier integration with other JS frameworks)
  • all JavaScript code is checked with ESLint
  • REDIPS.drag documentation generated with JsDoc Toolkit
  • drag and drop table rows
  • movable DIV element can contain other HTML code (images, forms, tables …)
  • forbidding or allowing TDs marked with class name “redips-mark”
  • option to define exceptions and allow dropping certain DIV elements to the marked cell
  • option to define single content cell on the table declared with “multiple” drop option
  • cloning
    • for unlimited cloning add “redips-clone” class name to the DIV object
      <div class=”redips-drag redips-clone”>Hello World</div>
    • to limit cloning and transform last object to the ordinary movable object add ‘climit1_X’ class name
      <div class=”redips-drag redips-clone climit1_4″>Hello World</div>
    • to limit cloning and transform last object to immovable object add ‘climit2_X’ class name
      <div class=”redips-drag redips-clone climit2_4″>Hello World</div>
    • where X is integer and defines number of cloned elements (in previous examples, each climit will allow only 4 cloned elements)
  • unlimited nested tables support
  • dropping objects only to empty cells
  • switch cell content
  • switching cell content continuously
  • overwrite TD content with dropped element
  • shift table content
  • table cell with “redips-trash” class name becomes trashcan
  • enabled handlers to place custom code on events: changed, clicked, cloned, clonedDropped, clonedEnd1, clonedEnd2, dblClicked, deleted, dropped, droppedBefore, finish, moved, notCloned, notMoved, shiftOverflow, relocateBefore, relocateAfter, relocateEnd, rowChanged, rowClicked, rowCloned, rowDeleted, rowDropped, rowDroppedBefore, rowDroppedSource, rowMoved, rowNotCloned, rowNotMoved, rowUndeleted, switched and undeleted
  • deleting cloned DIV if the cloned DIV is dragged outside of any table
  • enabling / disabling dragging
  • animation (move element/row to the destination cell/row)
  • added support for touch devices (touchstart, touchmove, touchend)

How REDIPS.drag works?

Script will search for DIV elements (with class name “redips-drag”) inside tables closed in <div id=”redips-drag”> and attach onMouseDown event handler. When user clicks with left mouse button on DIV element, onMouseMove and onMouseUp handlers will be attached to the document level.

While dragging DIV element, script changes its “left” and “top” styles. This is function of the onMouseMove handler. When user releases left mouse button, onMouseUp event handler will unlink onMouseMove and onMouseUp event handlers. This way, browser will listen and process mousemove events only when DIV element is dragged.

As I mentioned, onMouseDown is defined on the elements you want to drag. Elements beneath the dragged object will not be able to catch onMouseOver event. Why? Because you are dragging object and that object only can catch the onMouseOver event.

So, to detect destination table cells, script calculates all cell coordinates (with scroll page offset) and store them to the array. Array is searched inside onMouseMove handler and after left mouse button is released, DIV will drop to the current (highlighted) table cell.

In redips2.tar.gz package you will find many examples including example of how to save/recall table using PHP and MySQL. Package also contains and redips-drag-min.js – a compressed version of REDIPS.drag library (compressed with Google Closure Compiler).

Happy dragging and dropping!

1,195 thoughts on “Drag and Drop table content with JavaScript”

  1. Hi,
    Excellent & beautiful script. I was planning to use this for my Data Center capacity planning application to manage the blade servers and the rack usage. BTW I found there is a problem while trying with the IE8. Following js errors are shown. Hope this helps to debug the issue.
    ——————————————————————————–
    Webpage error details

    User Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB5; Embedded Web Browser from: bsalsa.com; .NET CLR 2.0.50727; InfoPath.2)
    Timestamp: Tue, 22 Sep 2009 11:08:32 UTC

    Message: ‘tables[…].rows’ is null or not an object
    Line: 129
    Char: 2
    Code: 0
    URI: file:///C:/Intranet%20Developments/drag.js/redips2/www_redips_net/drag.js

    Message: ‘tables[…].rows’ is null or not an object
    Line: 158
    Char: 3
    Code: 0
    URI: file:///C:/Intranet%20Developments/drag.js/redips2/www_redips_net/drag.js

    Message: ‘obj_margin.3’ is null or not an object
    Line: 245
    Char: 2
    Code: 0
    URI: file:///C:/Intranet%20Developments/drag.js/redips2/www_redips_net/drag.js

    Message: ‘obj_margin.3’ is null or not an object
    Line: 245
    Char: 2
    Code: 0
    URI: file:///C:/Intranet%20Developments/drag.js/redips2/www_redips_net/drag.js


  2. Nice script this is very useful to me. but i can use this code is display an error.pls try to give full website project

  3. This is very good code the only thing I don’t understand is what you mean by add .drag{position: relative;} class to your css (this is minimum). Do you set that as a name or what? Please reply as soon as you can

  4. @Michael Miller – Option “Remove cloned object if dragged outside of any table” is finished.

    @Ilir – script is improved and if you place image inside DIV (only image without <a href=”…), drag and drop will work in FF and IE. The catch was to put onmousemove=”return false” in IMG tag, or to register onmousemove event to images inside div=”drag” (like I did in window.onload). So, dragging images was solved, but how to add links to the images? That’s a little tricky because inner element (link) and his container (div) should register onmousedown event. IE and FF have different event orders so it seems not easy to implement now. Anyway, I suggest another approach. You can set ID for every image – for example <img src=”my_img.jpg” id=”323″>. In myhandler_notmoved handler, place few JS lines. If you click on image and release mouse button (without moving image around), this code will be executed:

    function myhandler_notmoved(){
        // if selected DIV element contains child elements
        if (obj.firstChild){
            // if child element is image
            if (obj.firstChild.tagName == ‘IMG’) window.location.href = ‘/some/page/script.php?img_id=’ + obj.firstChild.id;
        }
    }

    This way, you will have drag and drop functionality and links … Hope this tip will help you. What about forbidden cells? When user starts to drag DIV element, script remembers last possible drop position and that’s the case with forbidden cells too. After releasing button on dragged element over forbidden cell, element couldn’t be dropped to the forbidden cell but to the previous location.

    @Ricardo Rodrigues – Unfortunately, script only moves one element at time. I’m playing with drag and drop table rows, but the only problem in developing is lack of free time. ;)

    @SCB – Your question is, how to save two DIV’s from one table cell?. Please take a look at “table_content” function (fired on “Click” button). This function browses through each table and displays found content. If you place two DIV elements in one table cell, “table_content” function will display both elements with the same row and column coordinates. You only have to save row and column for each element. Just customize “table_content” to send parameters to your “save.php” …

    @Dushan – IE8 is new beast in town. My script should work with FF3, IE6/7, Google Chrome, Safari 4 and naov said it works in Opera 10. I will fix script to work with IE8 as soon as possible. Thank you for debug output.

    @Trent – If you want to drag and drop DIV elements with drag.js script, you only need to set “position: relative” style for DIV elements. Other styles (border, width, …) are not needed. I see that “(this is minimum)” sounds confusing, so I will remove it from this post.

  5. May I know how to obtain four headed arrows for some cells and not for some.
    Can I have the entire functionality code, since I am new to web applications.

  6. Hi,

    First of all, what a wonderfull script. I had something a lot less fancy in mind, but your script will add a lot of user comfort, if I get it to do what I want.

    Basically, I want the positions stored and remembered. A submit button to store the r and c variable in a db so that when the user returns the DIVs are placed where they were last time. But I cannot get it to work with my basic understanding of js and php. Could you hint me?
    Thanks!

  7. Thank you this is much better to understand now. However, I have been playing around with the code and I found that the images are not dragging. I want them to be able to be moved around from the tables individual cells. Therefore I am not requiring the clonning part of the code. What parts of the code would I need to use in order to do this?

  8. >>Option “Remove cloned object if dragged outside of any table” is finished.<<

    Very nicely done, Mr. Bunic – !

    My thanks to you for this very useful improvement in this (already) excellent script – !

    Your responsive support is greatly appreciated – !

    Kind Regards . . . michael miller

  9. Just want to say thanks very much. Wonderful script and easy to understand.

    Just wondered had you got any further with the ie8 bug as it is the only problem I am having.

    Regards,
    Stephen

  10. Elegant concept, and very useful. Could you consider wrapping it a bit more to have less entries in the global namespace? We also use several other frameworks, and it is nice to avoid any collisions.

  11. Hello!

    First – Thank you for making this code available to us!

    I’m really struggling trying to implement you script on one of my websites.
    When I drag and drops from one table to another – it will not settle inside the table, but ends outside the table. (under it)

    The “to” table has empty rows/elements.
    Non of the rows in the “to” table has any class !

    Any idea what this is ?

    Regards
    Steinar

  12. Hello again!
    I found the problem I have on my site – reported yesterday!

    I have my two tables nested inside two other tables – used for positioning !

    Is there any solution to allow this ?

    Thanks for your reply !

    regards
    Steinar

  13. @Dhurai – The cursor CSS property specifies the mouse cursor displayed when the mouse pointer is over an element. In class .drag you will find property “cursor: move”. More about CSS values of “cursor” you can read at CSS cursor. Entire source code you can get if you peek to the page source, but that can be hard to read. So I prepared redips2.tar.gz package.

    @Matti – “Click” button is replaced with “Save” button. After clicking on “Save” button, JS function will scan all tables, prepare query string and send to the PHP page. More about accepting parameters you can read in my post Reading multiple parameters in PHP.

    @Trent – Just place image inside <div id=”drag”></div> and image should be able to drag like smile in this demo.

    @Stephen – I tested drag and drop in IE8 but without any error. Did you try script locally from redips2.tar.gz package or directly on this post? I noticed weird behavior if I start dragging elements before page is loaded. This post has many elements, so sometimes needs few moments to load completely. Just guessing …

    @Jay Baker – You are right. Script should be rearranged – global variables are evil! I will try to wrap script to enable easy integration with other JS frameworks.

    @Steinar – I’m sorry, but nested tables aren’t supported yet.

  14. Unfortunately @dbunic this is not the case. I am getting the same error as @Dushan. It is when dragging from one table to another.

  15. Mr. dbunic,

    My compliments on your wonderfull script. The ‘Save’ update works wonders and I’ve got it fully functional. It is a very elegant tool that users will certainly appreciate.

    my best regards,
    Matti

  16. Hi
    Thank you that your code helped me in my Project.
    Also i learned and aware of something in Drag and Drop.

    Thanks Again !!!!!!!!!!!!!!!!!!!!!!!!!

  17. I do get saving everything to the database but what I dont get is how to recall it properly.

  18. I found my own way for calling the order of the tables using PHP foreach value needed for my Columns. I have it set up on the front page for each user to adjust the tables there own way. I broke down the table to 3 Columns. I also included a on/off toggle for not having to deal with clicking or page lag, because I noticed lag when the drag was active and there was to many bytes present.

    I would ask if you can for the future of others to include:

    1. On/Off Toggle.
    2. A Single Table Example along with what you have.
    3. Prewritten examples for properly saving the “Id=$id Table=$table Column=$column Row=$row”.
    4. PHP for calling the “Order” properly.

    ////////////////////////////////////////////////////////////////////
    Here is my fwrite example in multiple-parameters.php:
    (Im having the info saved to a users page)

    $handle = ‘user_file_example.php’;

    fwrite($handle, stripslashes(”)

    ////////////////////////
    Here is my Call Example on the index.php page:

    include “./users_file_example.php”; //its called by session

    $maketo[“d11”] = “./files/galleries.php”; //this is premade and will be set as include

    ////////////////////////////////////////////
    //This next code is set in each Table Column

    foreach( $tblsite as $key => $value){
    $findcol = ‘0’; //column 0,1,2 change as many needed
    if($value == $findcol){
    include ”.$maketo[$key].”; // it includes the file perfectly
    }
    }
    ////////////////DONE/////////////

    Honestly my coding is ugly, but I dont care. I get things done the way I want them. cheers

    Besides that, Awesome Script and Thank You!

  19. Unreal!:) You are awesome. Very nice script.

    I have one problem. If I have two tables. And I wan’t to drag and drop two rows to another table two rows or do the same with two cells is it possible?

Leave a Comment